using System;
using System.Collections.Generic;
using System.Text;
using agsXMPP;
using System.Data;
using agsXMPP.protocol.client;
using agsXMPP.protocol.iq.vcard;
using System.IO;
using agsXMPP.protocol.iq.disco;

namespace Blabber.Data
{
    public class CommunicationData
    {
        public delegate void MessageDelegate(object sender);

        System.Windows.Window _window;
        
        Dictionary<string, XmppClientConnection> _connections;

        Dictionary<string, agsXMPP.Jid> _rosterDictionary;
        Dictionary<string, Vcard> _rosterVCards;
        
        DataSetBlabber _data;
        DataView _rosterView;
        DataSetModel _model;

        string _loggedInJID;

        Boolean _connected = false;

        public event EventHandler MessageReceivedEvent; 

        public CommunicationData(System.Windows.Window window)
        {
            _rosterDictionary = new Dictionary<string, agsXMPP.Jid>();
            _rosterVCards = new Dictionary<string, Vcard>();

            _window = window;
            _data = new DataSetBlabber();
            _rosterView = new DataView(_data.RosterItem);

            _rosterView.Sort = "IsAvailable DESC, Show DESC, Name ASC";

            _connections = new Dictionary<string, XmppClientConnection>(); 
        }

        public string LoggedInJID
        {
            get { return _loggedInJID; }
            set { _loggedInJID = value; }
        }

        public Boolean Connected
        {
            get { return _connected; }
        }

        public DataSetBlabber Data
        {
            get { return _data; }
        }

        public DataView RosterView
        {
            get { return _rosterView; }
        }

        public Dictionary<string, agsXMPP.Jid> RosterDictionary
        {
            get { return _rosterDictionary; }
        }

        public DataSetModel Model
        {
            get { return _model; }
            set { _model = value; }
        }

        public void SetStatus(string status, int show)
        {
            foreach (XmppClientConnection connection in _connections.Values)
            {
                if (_connected)
                {
                    connection.Status = status;
                    connection.Show = (ShowType)show;

                    connection.SendMyPresence();
                }
            }
        }

        public void Open()
        {

            //if (File.Exists("roster.xml"))
            //{
            //    _data.ReadXml("roster.xml");
            //}

            agsXMPP.XmppClientConnection client;

            foreach (Blabber.Data.DataSetModel.ConnectionRow row in _model.Connection.Rows)
            {
                if (!_connections.ContainsKey(row.UserName))
                {
                    client = new XmppClientConnection(agsXMPP.net.SocketConnectionType.Direct);
                    client.KeepAlive = true;
                    client.AutoResolveConnectServer = true;
                    client.AutoRoster = true;
                    client.AutoPresence = true;
                    client.AutoAgents = true;

                    client.OnMessage += new MessageHandler(_client_OnMessage);
                    client.OnPresence += new PresenceHandler(_client_OnPresence);
                   
                    client.OnLogin += new ObjectHandler(_client_OnLogin);
                    client.OnReadXml += new XmlHandler(_client_OnReadXml);

                    client.OnRosterStart += new ObjectHandler(_client_OnRosterStart);
                    client.OnRosterItem += new XmppClientConnection.RosterHandler(_client_OnRosterItem);
                    client.OnRosterEnd += new ObjectHandler(_client_OnRosterEnd);
                    
                    client.OnError += new ErrorHandler(_client_OnError);

                    client.Server = row.Server;
                    client.ConnectServer = row.ConnectServer;
                    client.Port = row.Port;
                    client.Username = row.UserName;
                    client.Password = row.Password;

                    _connections.Add(string.Format("{0}@{1}", row.UserName, row.Server), client);

                    row.JID = string.Format("{0}@{1}", row.UserName, row.Server);
                }
            }

            foreach (XmppClientConnection connection in _connections.Values)
            {
                connection.Open();
            }

            _connected = true;
        }

        private void VCardConnectionResult(object sender, IQ iq, object data)
        {
            if (iq.Type == IqType.result)
            {
                Blabber.Data.DataSetModel.ConnectionRow row = (data as Blabber.Data.DataSetModel.ConnectionRow);
                if (null != row)
                {
                    Vcard vCard = iq.Vcard;

                    if (vCard.Photo != null)
                    {
                        MemoryStream ms = new MemoryStream();
                        vCard.Photo.Image.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
                        row.Image = ms.ToArray();
                    }
                    else
                    {
                        MemoryStream ms = new MemoryStream();
                        Blabber.Data.ResourceMain.anon.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
                        row.Image = ms.ToArray();
                    }
                }
            }
        }

        public void Close()
        {
            foreach (XmppClientConnection connection in _connections.Values)
            {
                SetStatus("Away", (int)ShowType.away);
                connection.Close();
            }

            _connections.Clear();
            _rosterDictionary.Clear();

            //_data.WriteXml("roster.xml");

            _data.RosterItem.Clear();

            _connected = false;
        }


        public void SendMessage(agsXMPP.Jid jid, string body)
        {
            agsXMPP.protocol.client.Message msg = new agsXMPP.protocol.client.Message();

            msg.Type = MessageType.chat;
            msg.To = jid;
            msg.Body = body;

            Blabber.Data.DataSetBlabber.RosterItemRow row = _data.RosterItem.FindByJID(jid.Bare);
            if (null != row)
            {
                if (_connections.ContainsKey(row.FromJID))
                {
                    _connections[row.FromJID].Send(msg);
                }
            }
        }

        public void SendFile(agsXMPP.Jid jid, string[] files)
        {
            Blabber.Data.DataSetBlabber.RosterItemRow row = _data.RosterItem.FindByJID(jid.Bare);
            if (null != row)
            {
                if (_connections.ContainsKey(row.FromJID))
                {
                    
                }
            }
        }

        private void FindChatRooms(string toJID)
        {
            DiscoItemsIq discoIq = new DiscoItemsIq(IqType.get);
            discoIq.To = new Jid(toJID);

            XmppClientConnection client = _connections[toJID];

            client.IqGrabber.SendIq(discoIq, new IqCB(OnGetChatRooms), null);
        }

        private void OnGetChatRooms(object sender, IQ iq, object data)
        {
            DiscoItems items = iq.Query as DiscoItems;
            
            if (items == null)
                return;

            DiscoItem[] rooms = items.GetDiscoItems();
            foreach (DiscoItem item in rooms)
            {
                
            }
        }

        #region Jabber Client Events

        void _client_OnError(object sender, Exception ex)
        {
            
        }

        void _client_OnRosterEnd(object sender)
        {

        }

        void _client_OnRosterStart(object sender)
        {

        }

        void _client_OnRosterItem(object sender, agsXMPP.protocol.iq.roster.RosterItem item)
        {
            if (!_connections.ContainsKey(item.Jid.Bare))
            {
                RosterItemMessage message = new RosterItemMessage();
                message.RosterItem = item;
                message.Client = (sender as agsXMPP.XmppClientConnection);

                _window.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new MessageDelegate(OnRosterItemHandler), message);
            }
            
        }

        void _client_OnReadXml(object sender, string xml)
        {

        }

        void _client_OnLogin(object sender)
        {
            _window.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new MessageDelegate(OnLoginReceivedHandler), sender);
        }

        void _client_OnPresence(object sender, Presence pres)
        {
            if (!_connections.ContainsKey(pres.From.Bare))
                _window.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new MessageDelegate(OnPresenceHandler), pres);
        }

        void _client_OnMessage(object sender, Message msg)
        {
            _window.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new MessageDelegate(OnMessageReceivedHandler), msg);
        }

        #endregion

        #region Delegate Methods

        

        public void OnLoginReceivedHandler(object sender)
        {
            agsXMPP.XmppClientConnection connection = (sender as agsXMPP.XmppClientConnection);
            connection.Status = "Available";
            connection.Show = ShowType.chat;
            connection.SendMyPresence();

            Blabber.Data.DataSetModel.ConnectionRow found = null;
            foreach (Blabber.Data.DataSetModel.ConnectionRow row in _model.Connection.Rows)
            {
                if (row.JID == connection.MyJID.Bare)
                {
                    found = row;
                    break;
                }
            }

            VcardIq viq = new VcardIq(IqType.get, connection.MyJID);
            string packetId = viq.Id;
            connection.IqGrabber.SendIq(viq, new IqCB(VCardConnectionResult), found);
        }

        public void OnPresenceHandler(object sender)
        {
            agsXMPP.XmppClientConnection client;
            Blabber.Data.DataSetBlabber.RosterItemRow row;

            agsXMPP.protocol.client.Presence pres = (sender as agsXMPP.protocol.client.Presence);

            if (_connections.ContainsKey(pres.To.Bare))
            {
                client = _connections[pres.To.Bare];

                if ((pres.Type == agsXMPP.protocol.client.PresenceType.available) ||
                    (pres.Type == agsXMPP.protocol.client.PresenceType.unavailable))
                {
                    row = _data.RosterItem.FindByJID(pres.From.Bare);
                    if (null != row)
                    {
                        if (pres.Type == agsXMPP.protocol.client.PresenceType.available)
                            row.IsAvailable = true;
                        else
                            row.IsAvailable = false;

                        VcardIq viq = new VcardIq(IqType.get, pres.From);
                        string packetId = viq.Id;
                        client.IqGrabber.SendIq(viq, new IqCB(VCardResult), null);

                        row.Status = pres.Status;
                        row.Show = pres.Show.ToString();
                    }
                    else
                    {
                        row = _data.RosterItem.NewRosterItemRow();
                        row.JID = pres.From.Bare;
                        row.FromJID = pres.To.Bare;

                        if (pres.Type == agsXMPP.protocol.client.PresenceType.available)
                            row.IsAvailable = true;
                        else
                            row.IsAvailable = false;

                        row.Status = pres.Status;
                        row.Show = pres.Show.ToString();

                        VcardIq viq = new VcardIq(IqType.get, pres.From);
                        string packetId = viq.Id;
                        client.IqGrabber.SendIq(viq, new IqCB(VCardResult), null);

                        _data.RosterItem.AddRosterItemRow(row);
                    }

                    if (!_rosterDictionary.ContainsKey(pres.From.Bare))
                        _rosterDictionary.Add(pres.From.Bare, pres.From);
                }
            }

        }

        public void OnRosterItemHandler(object sender)
        {
            RosterItemMessage message = (sender as RosterItemMessage);

            agsXMPP.protocol.iq.roster.RosterItem item = message.RosterItem;

            Blabber.Data.DataSetBlabber.RosterItemRow row;
            row = _data.RosterItem.FindByJID(item.Jid.Bare);

            if (null != row)
            {
                if (item.Name != null)
                    row.Name = item.Name;
                else
                    row.Name = item.Jid.User;

                row.JID = item.Jid.Bare;
                row.FromJID = message.Client.MyJID.Bare;
                row.IsAvailable = false;

                VcardIq viq = new VcardIq(IqType.get, item.Jid);
                string packetId = viq.Id;
                message.Client.IqGrabber.SendIq(viq, new IqCB(VCardResult), null);
            }
            else
            {
                row = _data.RosterItem.NewRosterItemRow();
                row.JID = item.Jid.Bare;
                row.FromJID = message.Client.MyJID.Bare;
                row.IsAvailable = false;

                if (item.Name != null)
                    row.Name = item.Name;
                else
                    row.Name = item.Jid.User;

                VcardIq viq = new VcardIq(IqType.get, item.Jid);
                string packetId = viq.Id;
                message.Client.IqGrabber.SendIq(viq, new IqCB(VCardResult), null);

                _data.RosterItem.AddRosterItemRow(row);
            }

            if (!_rosterDictionary.ContainsKey(item.Jid.Bare))
                _rosterDictionary.Add(item.Jid.Bare, item.Jid);
        }

        private void VCardResult(object sender, IQ iq, object data)
        {
            if (iq.Type == IqType.result)
            {
                Vcard vCard = iq.Vcard;
                if (!_rosterVCards.ContainsKey(iq.From.Bare))
                    _rosterVCards.Add(iq.From.Bare, vCard);

                Blabber.Data.DataSetBlabber.RosterItemRow row;
                row = _data.RosterItem.FindByJID(iq.From.Bare);
                if (null != row)
                {
                    if (vCard.Photo != null)
                    {
                        MemoryStream ms = new MemoryStream();
                        vCard.Photo.Image.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
                        row.Image = ms.ToArray();
                    }
                    else
                    {
                        MemoryStream ms = new MemoryStream();
                        Blabber.Data.ResourceMain.anon.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
                        row.Image = ms.ToArray();
                    }
                }
            }
        }

        public void OnMessageReceivedHandler(object sender)
        {
            agsXMPP.protocol.client.Message msg = (sender as agsXMPP.protocol.client.Message);

            if (null != MessageReceivedEvent)
                MessageReceivedEvent(msg, new EventArgs());
        }

        #endregion
    }

    public class RosterItemMessage
    {
        public agsXMPP.protocol.iq.roster.RosterItem RosterItem;
        public agsXMPP.XmppClientConnection Client;
    }
}
